package com.sh.serializer;


import com.fasterxml.jackson.databind.ObjectMapper;
import com.sh.model.RpcRequest;
import com.sh.model.RpcResponse;


import java.io.IOException;

/**
 * Json序列化器
 */
public class JsonSerializer implements Serializer{

    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    @Override
    public <T> byte[] serialize(T obj) throws Exception {
        return OBJECT_MAPPER.writeValueAsBytes(obj);   // 序列化
    }


    // 反序列化
    @Override
    public <T> T deserialize(byte[] bytes, Class<T> clazz) throws Exception {
        T obj = OBJECT_MAPPER.readValue(bytes, clazz);
        if ( obj instanceof RpcRequest){
            // 请求的序列化
            return handlerRequest((RpcRequest) obj, clazz);
        }
        if ( obj instanceof RpcResponse){
            // 响应的序列化
            return handlerResponset((RpcResponse) obj, clazz);
        }
        return obj;
    }




    // 请求的序列化处理
    private <T> T handlerRequest(RpcRequest rpcRequest, Class<T> type) throws IOException {
        // 参数类型数组
        Class<?>[] parameterType = rpcRequest.getParameterTypes();   // 参数类型数组
        // 参数数组
        Object[] args = rpcRequest.getArgs();   // 参数数组

        // 循环类型数组
        for (int i = 0; i < parameterType.length; i++) {
            // 获取当前类型
            // parameters[i]  // 每个类型对应的值    例如：content-type  ->  application/json
            Class<?> clazz = parameterType[i];

            // 判断类型是否匹配  如果不匹配
            if ( !clazz.isAssignableFrom(args[i].getClass()) ){
                // 不匹配也要让他匹配
                byte[] argBytes = OBJECT_MAPPER.writeValueAsBytes(args[i]);// 序列化为字节数组
                args[i] = OBJECT_MAPPER.readValue(argBytes, clazz);   // 反序列化为指定类型
            }
        }
        // 将RpcRequest转换为指定类型T并返回
        return type.cast(rpcRequest);
    }


    // 响应的序列化处理
    private <T> T handlerResponset(RpcResponse rpcResponse, Class<T> type) throws IOException{
        byte[] dataBytes = OBJECT_MAPPER.writeValueAsBytes(rpcResponse.getData());
        rpcResponse.setData( OBJECT_MAPPER.readValue(dataBytes, rpcResponse.getDataType()));
        return type.cast(rpcResponse);
    }
}
